﻿using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Kele.Core.Http
{
    [System.Runtime.InteropServices.Guid("BB1AE61E-1D5B-4AB2-A770-AD481EF97695")]
    public static class HttpRequestExtensions
    {
        public static string GetClientIp(this HttpContext context)
        {
            string ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(ip))
            {
                ip = context.Connection.RemoteIpAddress.ToString();
            }
            return ip;
        }

        public static Dictionary<string, string> GetQueryDictionaryAsync(this HttpRequest request)
        {
            return request.Query.ToDictionary(k => k.Key, v => v.Value.ToString());
        }

        /// <summary>
        /// Retrieves the raw body as a byte array from the Request.Body stream
        /// </summary>
        /// <param name="request">Request instance to apply to</param>
        /// <param name="inputStream">Optional - Pass in the stream to retrieve from. Other Request.Body</param>
        /// <returns></returns>
        public static async Task<byte[]> GetRawBodyBytesAsync(this HttpRequest request, Stream inputStream = null)
        {
            if (inputStream == null) inputStream = request.Body;
            await using var ms = new MemoryStream(2048);
            await inputStream.CopyToAsync(ms);
            return ms.ToArray();
        }

        /// <summary>
        /// Retrieve the raw body as a string from the Request.Body stream
        /// </summary>
        /// <param name="request">Request instance to apply to</param>
        /// <param name="encoding">Optional - Encoding, defaults to UTF8</param>
        /// <param name="inputStream">Optional - Pass in the stream to retrieve from. Other Request.Body</param>
        /// <returns></returns>
        public static async Task<string> GetRawBodyStringAsync(this HttpRequest request, Encoding encoding = null, Stream inputStream = null)
        {
            if (encoding == null) encoding = Encoding.UTF8;
            if (inputStream == null) inputStream = request.Body;
            using var reader = new StreamReader(inputStream, encoding);
            return await reader.ReadToEndAsync();
        }

        /// <summary>
        /// Returns the absolute Url of the current request as a string.
        /// </summary>
        /// <param name="request"></param>
        public static string GetUrl(this HttpRequest request)
        {
            return $"{request.Scheme}://{request.Host}{request.Path}{request.QueryString}";
        }

        public static bool IsAjaxRequest(this HttpRequest request)
        {
            return string.Equals(request.Query["X-Requested-With"], "XMLHttpRequest", StringComparison.Ordinal)
                || string.Equals(request.Headers["X-Requested-With"], "XMLHttpRequest", StringComparison.Ordinal);
        }

        public static bool IsJsonContextType(this HttpRequest request)
        {
            bool flag = request.Headers?["Content-Type"].ToString().IndexOf("application/json", StringComparison.OrdinalIgnoreCase) > -1
                || request.Headers?["Content-Type"].ToString().IndexOf("text/json", StringComparison.OrdinalIgnoreCase) > -1;
            if (flag)
            {
                return true;
            }
            flag = request.Headers?["Accept"].ToString().IndexOf("application/json", StringComparison.OrdinalIgnoreCase) > -1
                || request.Headers?["Accept"].ToString().IndexOf("text/json", StringComparison.OrdinalIgnoreCase) > -1;
            return flag;
        }

        /// <summary>
        /// Returns a value based on a key against the Form, Query and Session collections
        /// </summary>
        /// <param name="request"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string Params(this HttpRequest request, string key)
        {
            var value = request.Form[key].FirstOrDefault();
            if (string.IsNullOrEmpty(value))
                value = request.Query[key].FirstOrDefault();
            return value;
        }
    }
}